articles

Home / DeveloperSection / Articles / Retrieving and displaying data from a RESTful API in Knockout JS

Retrieving and displaying data from a RESTful API in Knockout JS

Retrieving and displaying data from a RESTful API in Knockout JS

Ravi Vishwakarma 416 27-May-2024

Retrieving and displaying data from a RESTful API involves several steps. Here, I'll outline the general process and provide a Python code example using the requests library to interact with a RESTful API and display the data.

 

Steps to Retrieve and Display Data from a RESTful API

  1. Choose the API and endpoint: Identify the API you want to use and the specific endpoint from which you want to retrieve data. Ensure you have any necessary API keys or authentication tokens.
  2. Install required libraries: For Python, you'll typically use the requests library to make HTTP requests. If not already installed, you can install it using pip.
  3. Make the HTTP request: Use the requests library to send a GET request to the API endpoint.
  4. Handle the response: Check the response status code to ensure the request was successful. Parse the JSON data from the response.
  5. Display the data: Extract and display the relevant information from the JSON data.

 

Step 1: Include Knockout.js Library

Make sure you have included the Knockout.js library in your HTML file. You can either download it and host it locally or include it from a CDN.

<!-- Link to Bootstrap CSS for styling -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">

    <!-- Link to Knockout.js library for MVVM pattern support -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.min.js"
        integrity="sha512-vs7+jbztHoMto5Yd/yinM4/y2DOkPLt0fATcN+j+G4ANY2z4faIzZIOMkpBmWdcxt+596FemCh9M18NUJTZwvw=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>

    <!-- Link to jQuery library -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

Step 2: Define ViewModel

Create a ViewModel in JavaScript. This ViewModel will hold the data retrieved from the API and bind it to the HTML.

class AppViewModel {
    constructor() {
        var self = this;
        self.response = ko.observable({});
        self.currentPage = ko.observable(0);
        self.totalPages = ko.observable(0);
        self.pagination = ko.observable({});

        self.isLoading = ko.observable(false);
        self.error = ko.observable(null);
        self.fetchData = async function (url = '') {
            self.isLoading(true);
            self.error('');
        };
    }
}
// Apply bindings
ko.applyBindings(new AppViewModel());

Step 3: Bind Data to HTML

Use Knockout data binding syntax to bind the data from the ViewModel to HTML elements.

<!doctype html>
<html lang="en">

<head>
    <!-- Meta tags for character set and viewport configuration -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Title of the webpage -->
    <title>Bootstrap demo</title>

    <!-- Link to Bootstrap CSS for styling -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">

    <!-- Link to Knockout.js library for MVVM pattern support -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.min.js"
        integrity="sha512-vs7+jbztHoMto5Yd/yinM4/y2DOkPLt0fATcN+j+G4ANY2z4faIzZIOMkpBmWdcxt+596FemCh9M18NUJTZwvw=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>

    <!-- Link to jQuery library -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>

<body>
    <!-- Main container for the content -->
    <div class="container my-3">
        <!-- Header for the section -->
        <h2>Data from Server async</h2>
        <!-- Button to fetch data -->
        <button data-bind="click: fetchData('')" class="btn btn-secondary">Fetch Data</button>
        <hr />
        <div id="app">
            <!-- Display loading state -->
            <div data-bind="visible: isLoading">
                <div class="d-flex justify-content-center fw-semibold fs-5 align-items-center">
                    <span class="me-2">Loading...</span>
                    <div class="spinner-border" role="status">
                        <span class="visually-hidden">Loading...</span>
                    </div>
                </div>
            </div>

            <!-- Display error message if any -->
            <div class="d-flex justify-content-center fw-semibold fs-5 align-items-center"
                data-bind="visible: error, text: error" style="color: red;"></div>
            <div class="my-3 d-flex justify-content-end align-items-baseline">

                <span class="fw-semibold me-3" data-bind="with: { pages : pagination()}">
                    <span data-bind="text: pages.current_page"></span>
                    <span class="mx-1">of</span>
                    <span class="" data-bind="text: pages.total_pages"></span>
                </span>

                <ul class="pagination " data-bind="with: { pages : pagination(), prevUrl: pagination().prev_url, nextUrl: pagination().next_url, currentPage: pagination().current_page }">
                    <li class="page-item" data-bind="css: { 'disabled': !(currentPage > 1) }">
                        <a class="page-link" href="#"
                            data-bind="click: function() { $root.fetchData(''); }">
                            First
                        </a>
                    </li>
                    <li class="page-item" data-bind="css: { 'disabled': !(currentPage > 1) }">
                        <a class="page-link" href="#" 
                           data-bind="click: function() { $root.fetchData(prevUrl); }, 
                                      enable: (currentPage > 1)">
                            Previous
                        </a>
                    </li>
                    <li class="page-item active"><a class="page-link" href="#" data-bind="text: currentPage"></a></li>
                    <li class="page-item" data-bind="css: { 'disabled': !(currentPage < pages.total_pages) }">
                        <a class="page-link" href="#" 
                           data-bind="click: function() { $root.fetchData(nextUrl); }">
                            Next
                        </a>
                    </li>
                    <li class="page-item" data-bind="css: { 'disabled': !(currentPage < pages.total_pages) }">
                        <a class="page-link" href="#" 
                           data-bind="click: function() { $root.fetchData('https://api.artic.edu/api/v1/artworks?page='+pages.total_pages); }">
                            Last
                        </a>
                    </li>
                </ul>
                
            </div>
            <!-- Display data if available -->
            <div class="row g-3 row-cols-1 row-cols-md-2 row-cols-lg-3 row-cols-xl-4"
                data-bind="visible: !isLoading(), foreach: response().data">
                <!-- Column for each item -->
                <div class="col">
                    <!-- Card to display item details -->
                    <div class="card ">
                        
                        <img data-bind="if: (image_id || thumbnail), attr: {
                            src: 'https://www.artic.edu/iiif/2/' + image_id + '/full/400,/0/default.jpg',
                            alt: thumbnail ? thumbnail.alt_text : ''
                        }" class="card-img-top" height="250">


                        <div class="card-body">
                            <!-- Card title bound to item's title -->
                            <h5 class="card-title text-capitalize" data-bind="text: title"></h5>
                            <!-- Card text bound to item's body -->
                            <!-- <p class="card-text" data-bind="text: body"></p> -->
                        </div>
                        <div class="card-footer border-0 pt-0">
                            <!-- Footer with item id and a link -->
                            <p class="m-0 d-flex justify-content-between">
                                <!-- Item id displayed -->
                                <span class="fs-5 fw-bold" data-bind="text: id"></span>
                                <!-- Link to comments page for the item -->
                                <a data-bind="attr: { 'data-link': api_link }">
                                    <!-- SVG icon inside the link -->
                                    <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor"
                                        class="bi bi-arrow-right-circle-fill" viewBox="0 0 16 16">
                                        <path
                                            d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0M4.5 7.5a.5.5 0 0 0 0 1h5.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3a.5.5 0 0 0 0-.708l-3-3a.5.5 0 1 0-.708.708L10.293 7.5z" />
                                    </svg>
                                </a>
                            </p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Link to external JavaScript file -->
    <script src="app.js"></script>
</body>

</html>

Step 4: Make AJAX Request to API

Inside the fetchData function of your ViewModel, use AJAX (e.g., jQuery's $.ajax) to make a GET request to the RESTful API endpoint and update the artworks observable with the retrieved data.

self.fetchData = async function (url = '') {
            self.isLoading(true);
            self.error('');
            let _url = url || 'https://api.artic.edu/api/v1/artworks'; // Default URL
            try {
                // Simulate an asynchronous API call using fetch
                let response = await fetch(_url);
                if (!response.ok) {
                    throw new Error('Network response was not ok ' + response.statusText);
                }
                let result = await response.json();
                // console.log(result);
                self.response(result); // Update the observable array with the fetched data
                // Extract pagination data from the response and update observables accordingly
                if (result.pagination) {
                    self.pagination(result.pagination);
                }
            } catch (err) {
                self.error(err.message);
            } finally {
                self.isLoading(false);
            }
        };

Conclusion

This example demonstrates how to use Knockout.js to retrieve data from a RESTful API and bind it to HTML elements. Make sure to handle errors appropriately and customize the code according to your specific API and requirements.

 

Thanks for reading.

 


Ravi Vishwakarma is a dedicated Software Developer with a passion for crafting efficient and innovative solutions. With a keen eye for detail and years of experience, he excels in developing robust software systems that meet client needs. His expertise spans across multiple programming languages and technologies, making him a valuable asset in any software development project.

Leave Comment

Comments

Liked By